home *** CD-ROM | disk | FTP | other *** search
/ MIDICraft's MIDINET CD-ROM / MIDICraft's MIDINET CD-ROM.iso / DOSUTILS / MIDIMAP.ZIP / MIDIIO.DOC < prev    next >
Text File  |  1997-03-05  |  17KB  |  467 lines

  1.         ******************************
  2.             MIDIIO v1.7
  3.     
  4.            standard midi input and output for C++
  5.               by Guenter Nagler
  6.                 1995 
  7.           (gnagler@ihm.tu-graz.ac.at)
  8.         ******************************
  9.  
  10. [0] FEATURES
  11.     + parses binary midi files
  12.     + writes binary midi files
  13.     + copies binary midi files
  14.     + sorts midi events by time
  15.     + maps channels of binary midi files
  16.     + checks validity of binary midi files
  17.  
  18. [1] BACKGROUND
  19. My first midi parser was written in programming language "C".
  20. It was impossible to reuse the C code in other programs in slightly
  21. modified ways without duplicating the code.
  22.  
  23. In combination with the class facilities of "C++" (invented 1983 by
  24. B. Stroustrup) it is very simple to reuse source code.
  25.  
  26. For my midi purpose I only needed to pack the knowhow of midi file format
  27. parsing into a virtual base class. This class reads the midi file and
  28. validates it. For all information in the midi song the parser calls a
  29. function that usually does nothing in the base class but can be overwritten
  30. in derived classes so that the owner of the derived class can act on midi
  31. events like in event oriented programming method.
  32.  
  33. I used the midiio classes in various utilities:
  34.  
  35. + The program midi2txt shows how the midi events are fired by the midi parser.
  36. + The program midifmt shows how to get the header information of a midi file
  37.   using the midi parser.
  38. + The program midi2gm shows how midi files can be copied with
  39.   modifications.
  40.  
  41. My wish to port the module and other utilities to Macintosh environment 
  42. failed because some Macintosh users told me that file handling is very 
  43. different to other machines.
  44.  
  45. [2] FILES DESCRIPTION
  46.  
  47. MIDIIO.CPP..........C++ implementation of midi parser and midi writer
  48. MIDIIO.HPP..........C++ class definitions of midi parser and midi writer
  49. MIDIIO.DOC..........some help to the C++ classes
  50.  
  51. [3] COPYRIGHT
  52.  
  53. MIDIIO (c) 1995 was created by Guenter Nagler.
  54.  
  55. MIDIIO is free and may be used as you wish with this one exception:
  56.  
  57.     You may NOT charge any fee or derive any profit for distribution
  58.     of MIDIIO.  Thus, you may NOT sell or bundle MIDIIO with any
  59.     product in a retail environment (shareware disk distribution, CD-ROM,
  60.     etc.) without permission of the author.
  61.  
  62. You may give MIDIIO to your friends, upload it to a BBS, or ftp it to
  63. another internet site, as long as you don't charge anything for it.
  64.  
  65. [4] DISCLAIMER
  66.  
  67. MIDIIO was designed to handle 100% compatible midi files.
  68. It was tested with 600 different midi files but I can not say if 
  69. each 100% midi compatible midi file can be correctly converted.
  70. So I give no guarantees of the results, especially with non 100% 
  71. compatible midi files.
  72. If you find a midi file that you think to be 100% compatible midi
  73. that is not correctly parsed or copied, please send a sample file to
  74. gnagler@ihm.tu-graz.ac.at . 
  75.  
  76. Use MIDIIO at your own risk.  Anything you do with MIDIIO is your
  77. responsibility, and not the author's.  Any damage caused to any person,
  78. computer, software, hardware, company, or business by running MIDIIO
  79. is your responsibility, and the author will not be liable.
  80.  
  81. If you don't understand these terms, or are not sure of something, or
  82. are afraid something bad might come of using MIDIIO, don't  use  it!
  83. You are here forewarned.
  84.  
  85. [5] Compile
  86.  
  87. Use a C++ compiler to compile and link
  88.  
  89. e.g.
  90.  
  91.    g++ -o program program.cpp midiio.cpp otherfiles.cpp
  92.  
  93. Force the compiler to compile C++ code!
  94. Some compilers use the file extension to decide compile mode.
  95. If you compiler compiles only .C files then rename the file extension.
  96.  
  97.  
  98. [6] USAGE
  99. midiio.hpp defines following classes:
  100.  
  101. class MidiRead;
  102. class MidiWrite;
  103. class MidiCopy;
  104. class MidiSerial;
  105.  
  106. Include the header file into your source:
  107. #include "midiio.hpp"
  108.  
  109. CONSTRUCTION
  110.  
  111. All of theses need a filename to construct an instance of this class.
  112. The class opens or creats a file with that filename.
  113. MidiRead and MidiCopy allow to use an already opened file handle, so that
  114. the filename is only stored but not used by the base classes.
  115. The constructors do not write or read data.
  116.  
  117. Dynamic construction of a parser class:
  118.  
  119.     MidiRead *read = new MidiRead(input_filename);
  120.  
  121. Automatic construction of a writer class:
  122.  
  123.     MidiWrite midiwrite(output_filename);
  124.  
  125. Construction of a class using an open file:
  126.  
  127.     FILE* inputf = fopen(input_filename, READ_BINARY);
  128.     if (!inputf)
  129.       error...
  130.     MidiCopy midicopy(input_filename, inputf);
  131.  
  132. Construction of a serial midi reader: 
  133.         MidiSerial* serial = new MidiSerial(input_filename);
  134.  
  135. TEST IF CONSTRUCTION WAS SUCCESSFUL
  136.  
  137.     MidiRead* midiread = new MidiRead(filename);
  138.     if (!midiread)
  139.       not enough memory
  140.     else if (midiread->getf())
  141.       file filename not found
  142.     else
  143.       use midiread as parser
  144.  
  145. DESTRUCTION
  146.  
  147. If automatic construction was used then destructor is called automatically.
  148. if dynamic construction was used (new ...) then you must call delete operator
  149.  
  150.   MidiRead* midiread = new MidiRead(filename);
  151.   ...
  152.   delete midiread;
  153.  
  154. The destructor frees memory allocated by the class and finishs writing of
  155. midi files and closes the file if it was opened by the class constructor.
  156.  
  157.  
  158. PARSING MIDI FILES
  159.  
  160. Following functions parse midi files or parts of midi files:
  161.   int run();         // parses full midi file
  162.   int runhead();     // parses only header of midi file
  163.   int runtrack(int trackno);   // parses a single track 
  164.   int runevent(long trackend);    // parses a single midi event
  165.  
  166. run() and runhead() automatically parse from the beginning of the file.
  167. run() automatically calls the other functions for parsing special parts
  168. of the file. In MidiRead and MidiCopy run() delivers events tracks by tracks.
  169. In MidiSerial it delivers events sorted by time.
  170.  
  171. For direct use of runtrack() and runevent() the file must be positioned
  172. to a valid file position (use MidiRead::seek) that it will work properly.
  173. (E.g. you get the file positions by running in different passes, first
  174.   call run() and collect positions when reaching the position of track 
  175.   or certain event, and call runtrack() or runevent() when run()  is ready,
  176.   see mididrum.cpp for use of these special parsing technic).
  177.  
  178. Following functions are called by the parser while working or 
  179. when errors are found:
  180.  
  181. virtual void error(const char* msg); // found midi file format error, you should abort the procedure
  182. virtual void warning(const char* msg); // found harmless error or incompatibility
  183. virtual void percent(int perc);     // percentage 0..100 of parsed midi file, could be confusing if not 
  184.                 // sequentially parsing like run() does
  185.  
  186. run() and runhead() call the function head() with header information:
  187.     virtual void head(unsigned version, unsigned tracks, unsigned unitperbeat);
  188.  
  189. run() calls the function end() at end of midi file parsing
  190.  
  191. run() runtrack() call the functions 
  192.  
  193. virtual void track(int trackno, long length, int channel); // at beginning of a track
  194. virtual void endtrack(int trackno); // at end of a track
  195.  
  196. A track is a part of a song played by a certain group of instruments.
  197. All tracks are playing together at same time.
  198.  
  199. run() and runtrack() call the time() function between all midi events
  200. that delivers the pause between two midi events of this track.
  201. run() and runtrack() call runevent() to parse single events.
  202.  
  203. runtrack() can be aborted by setting member variable skiptrack_ to 1.
  204.  
  205. runevent() calls a function for each different midi event type.
  206. Some event types belong to a group and an option flag controls if 
  207. the group function or the specialized functions are called.
  208.  
  209. The option OPTION_NOCONTROLS controls if the function control() is called
  210. rather than one of the functions:
  211.     highbank(), wheel(), breath(), foot(), portamentotime(), data(), 
  212.     volume(), balance(), expression(), lowbank(), hold(), reverb(), 
  213.     chorus(), datainc(), datadec()
  214.  
  215. The option OPTION_NOEVENTS controls if the function rather calls only track() and endtrack()
  216. or the time() and all the midi event functions functions too.
  217.  
  218. The option OPTION_NOMETAEVENTS controls if the function meta() is called
  219. rather than one of the functions
  220.     seqnumber(), smpteofs(), key(),    prefixchannel(), prefixport(),
  221.     text(),    end(), tact(), tempo()
  222.  
  223. The option OPTION_NOSYSEVENTS  controls if the function sysex() is called
  224. rather than one of the functions 
  225.     gmreset(), gsreset(), gsexit()
  226.  
  227. In case that the special coding is not known as standard event the 
  228. group function is called.
  229.  
  230. The parser options can be assigned to the public member variable
  231. MidiRead::options_ . If more than one options are set then use the | operator
  232. to combine them (e.g. midiread->options_ = OPTION_NOSYSEVENTS | OPTION_METAEVENTS; ). By default all special functions are called rather than their
  233. group function.
  234.  
  235. Group functions help to treat events of same type common, if it is not
  236. not necessary to distinguish them.
  237.  
  238. See midi2txt implementation as a good example for the midi parser.
  239.  
  240. See midifade implementation as example for calculating midi time to 
  241. real time.
  242.  
  243. See mididmp implementation as example for sorting midi events by real time.
  244.  
  245. WRITING MIDI FILES
  246.  
  247. 1. construct an instance of a midi writer
  248.     MidiWrite *midiwrite = new  MidiWrite(output_filename);
  249.     if (!midiwrite)
  250.       error out of memory
  251.     if (!midiwrite.getf())
  252.       error cannot create file 
  253.  
  254. 2. generate the midi header
  255.     midiwrite->head(VERSION_SINGLECHANNEL, 0, resolution);
  256.  
  257.    You need to know with format you want to write:
  258.    VERSION_SINGLECHANNEL:  only one track that contains whole song (preferred format)
  259.    VERSION_MULTICHANNEL:   a tempo track and one or more tracks that 
  260.                contain only events of certain midi channel
  261.                (different tracks could use same channel)
  262.    VERSION_MULTISONG:       each track contains a whole song (rarely used)
  263.  
  264.    You need to know which note resolution (= units per quarternote) you use:
  265.    Usually values 96, 120, 384 are used.
  266.    The value should be computable by:    resolution = 3 * 2 * 2 * 2 * ... * 2
  267.  
  268.    The number of tracks will be updated automatically, when the destructor of the 
  269.    class is called.
  270.  
  271. 3. generate track
  272.    midiwrite->track(); 
  273.  
  274.    it depends on the chosen format (version) which events you should 
  275.    generate in this track:
  276.    
  277.    VERSION_SINGLECHANNEL:
  278.       first track (tempo track) should contain only events that have no
  279.       channel parameter,
  280.       for each other track you should select one channel (0-15) and use
  281.       events that have no channel parameter or events generated with this 
  282.       channel number. Only the first track should contain tempo or tact
  283.       events.
  284.  
  285.    VERSION_MULTICHANNEL:    
  286.       Only one track is to generate and contains any events.
  287.  
  288.    VERSION_MULTISONG:
  289.       Each track is a song (as in VERSION_MULTICHANNEL) and contains 
  290.       any events.
  291.  
  292. 4. generate pause to start of next event
  293.    midiwrite->time( pause_units );
  294.    
  295.    A quarternote has  midiwrite->unitsperquarter()  midi units.
  296.  
  297.    The time will be written to the file when you generate an event or
  298.    close the track.
  299.    You can call it several and the function will add it to the current pause.
  300.  
  301.    The function getcurtime() delivers the total midi time units since start
  302.    of the track inclusive already chosen pause to the following event.
  303.  
  304.    You can reset current pause to 0 with call of function cleardelta().
  305.  
  306.    You can set current pause to a certain value by following sequence:
  307.     midiwrite->cleardelta();
  308.     midiwrite->time(newpause);
  309.  
  310. 5. generate event
  311.    use one of many event functions:
  312.  
  313.    Some functions are usable for a whole group of events:
  314.  
  315. void event(int what, int len, unsigned char* data); // write any event
  316. void meta(int what, int len, unsigned char* data); // write meta events
  317. void sysex(int syslen, unsigned char* sysdata); // write sysex events
  318. void text(int what, int len, unsigned char* txt); // write text meta events
  319.      // use defines meta_ in header for what parameter
  320. void control(int channel, int what, int val);   // write control event
  321.  
  322. The special events are similiar to the events in the midi parser.
  323.  
  324. 6. closing the track
  325.   You can enter pauses and events as many as you want into a track.
  326.   When you are ready you should close the track:
  327.  
  328.   midiwrite->endtrack();
  329.  
  330.   This will call MidiWrite::end() automatically to append an end of track
  331.   event to the track once and updates the length of the track.
  332.  
  333. 7. closing the midi file
  334.   Repeat writing tracks until enough tracks are written.
  335.   The midifile is finished when the destructor of the class is called.
  336.  
  337.   Therefor you use
  338.       delete midiwrite
  339.   or wait until the program leaves the block { ... } wherein the
  340.   instance was automatically constructed.
  341.  
  342.   The destructor updates the length of the file, updates the number of
  343.   tracks and flushes cached data to the file.
  344.  
  345.   if  the file was opened by the class itself the file handle is
  346.   closed automatically, otherwise you need to close it after the
  347.   class was destructed.
  348.  
  349.   Now the midi file is ready.
  350.   Use midi2txt to test if the resulting file is valid and contains
  351.   the correct information.
  352.  
  353.   See midi0to1 and midi1to0 how midi files are read and stored in an other format.
  354.  
  355. MODIFIYING MIDI FILES
  356.   The class MidiCopy reads a midifile and writes it in same format
  357.   to another file. While copying the channels can be mapped.
  358.  
  359.   By derivation of class MidiCopy minor changes to the
  360.   file are possible.
  361.  
  362. 1. derivation of class MidiCopy
  363.  
  364. class MidiChange : public MidiCopy
  365. {
  366. public:
  367.   MidiChange(char* name);
  368.  
  369.   virtual void track(int trackno, long length, int channel);
  370.   // specify all virtual functions that change
  371. };
  372.  
  373. void MidiChange::track(int trackno, long length, int channel)
  374. {
  375.     MidiChange::track();
  376.  
  377.     // e.g. add some events at beginning of track
  378.     char* copyright = "(c) G. Nagler";
  379.     MidiChange::text(meta_copyright, strlen(copyright), "copyright", copyright);
  380. }
  381.  
  382. 2. construct a parser object from own type
  383.  
  384.   MidiChange midi(input_filename);
  385.   if (!midi.getf())
  386.     error cannot open ...
  387.  
  388. 3. construct a midi writer object
  389.   MidiWrite* write = new MidiWrite(output_filename);
  390.   if (!write)
  391.     error not enough memory
  392.   if (!write->getf())
  393.     error cannot create midi file
  394.  
  395. 4. connect midi parser and midi writer
  396.   midi.setoutput(write);
  397.  
  398. 5. set channel mapping option if wanted
  399.   for (int c = 0; c < 16; c++)
  400.     midi.mapchannel(c, map[c]);
  401. 6. set channel ignore option if wanted
  402.   midi.ignorechannel(9);
  403.  
  404. 7. set parser options if wanted
  405.   midi.options_ = OPTION_NOEVENTS;
  406.  
  407. 8. start midi parser
  408.   if (!midi.run())
  409.     fprintf(stderr, "%s: midi read error at %04lX\n", input_filename, midi.getpos());
  410.  
  411. 9. close output midi file by destructing object
  412.   delete write;
  413.  
  414. You can add events, ignore events, replace events using this technic:
  415. e.g. change volume, change speed, change programs, transpose notes, ...
  416.  
  417. See midi2gm example that adds and ignores events to make midi files more
  418. general midi compatible.
  419.  
  420. Use getcurunit() to ask current in midi units.
  421. Use getcurmillisec() to ask current time since start of track.
  422. Hints:
  423.   Use this time information only in first track and
  424.   do not specify option OPTION_NOREALTIMEEVENTS or OPTION_NOMETAEVENTS
  425.   because these options ignore tempo changes and tempo changes are
  426.   only available in first track.
  427.  
  428. [7] SUGGESTIONS / COMMENTS / BUG REPORTS / QUESTIONS
  429.  
  430.          WWW:    http://hgiicm.tu-graz.ac.at/Cpub
  431.           contains all my dos/unix midi programs
  432.          EMAIL:  gnagler@ihm.tu-graz.ac.at
  433.  
  434. [8] CHANGES
  435. v1.0 to v1.1:
  436.   * some portability changes for UNIX compatibility
  437.  
  438. v1.1 to v1.2
  439.   * midiio engine writes less compressed but safer files (more compatibility
  440.     to weak midi readers)
  441.  
  442. v1.2 to v1.3
  443.   * added option -version
  444.   * added class MidiCopy for modifying midi files
  445.  
  446. v1.3 to v1.4
  447.   * better sysex support (unusual and elder variants)
  448.   * all functions are of MidiRead are now public, that reading midi files
  449.     can be done without functions runhead() runevent(), runtrack(), run()
  450.  
  451. v1.4 to v1.5
  452.   * File I/O in separate base class MidiBuffer
  453.   * MidiBuffer allows preloading loading of file into memory
  454.   * MidiBuffer allows work on memory midi data (in DOS realtime mode 
  455.     limited to 32 KB!, in protected mode or 32bit environments not limited)
  456.   * MidiRead: current time position available by function getcurmillisec()
  457.   * MidiRead: current beat number available by function getcurbeat()
  458.  
  459. v1.5 to v1.6:
  460.   * added class MidiSerial that reads a midi file and delivers events 
  461.     sorted by time (also see sample program midinote.zip)
  462.  
  463. v1.6 to v1.7:
  464.   * added skiptrack_ member to abort function runtrack if wanted
  465.   * removed exit(1) if track is incomplete, trying to skip the track with
  466.     skiptrack_
  467.